/*!
 * avangard/chat/channel.js
 * © 2009 avangardonline.ru
 * @author BlooDHounD <http://www.controller.by>
 */

if ( !window.controller ) throw new Error( '"controller" not initialized' );

controller.require( 'avangard.chat' );

if ( !avangard.chat.Channel ) {

	controller.require( 'controller.Logger' );

	/**
	 * @class
	 * @namespace	avangard.chat
	 * @extends		controller.events.EventDispatcher
	 * @requires	controller.Logger
	 * @requires	avangard.Character
	 * @author		BlooDHounD	<http://www.controller.by>
	 */
	avangard.chat.Channel = ( function() {

		//--------------------------------------------------------------------------
		//
		//  Class variables
		//
		//--------------------------------------------------------------------------

		/**
		 * @private
		 */
		var	$ =			controller,
			EEvent =	$.events.Event,

			EE_A =		'added',
			EE_R =		'removed',

			_e1 =		'absent reference to the character',
			_e2 =		'character with id "%s" has already been added',
			_e3 =		'character with name "' + name + '" never been added';

		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------

		/**
		 * @constructor
		 * @param	{Number}	id
		 * @param	{Number}	type
		 * @param	{String}	name
		 */
		var Channel = function(id, type, name) {
			//alert("Channel "+name+" "+type+" "+id);
			ChannelSuperPrototype.constructor.call( this );
			this.id =			id;
			this.type =			type;
			this.name =			name;
			this.logger =		new $.Logger( 150, 10*60e3, 50 );
			this._id_hash =		new Object();
			this._name_hash =	new Object();
		};

		$.extend( Channel, $.events.EventDispatcher );

		var	ChannelPrototype =		Channel.prototype,
			ChannelSuperPrototype =	Channel.superPrototype;

		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------

		/**
		 * @property
		 * @type	{Number}
		 */
		ChannelPrototype.id = 0;

		/**
		 * @property
		 * @type	{Number}
		 */
		ChannelPrototype.type = 0;

		/**
		 * @property
		 * @type	{String}
		 */
		ChannelPrototype.name = null;

		/**
		 * @property
		 * @type	{controller.Logger}
		 */
		ChannelPrototype.logger = null;

		/**
		 * @private
		 */
		ChannelPrototype._id_hash = null;

		/**
		 * @private
		 */
		ChannelPrototype._name_hash = null;

		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------

		/**
		 * @method
		 * @param	{avangard.Character}	character
		 * @throws	{Error}					absent reference to the character
		 * @throws	{Error}					character with id has already been added
		 * @throws	{Error}					character with name has already been added
		 */
		ChannelPrototype.addCharacter = function(character) {
			if ( !character ) throw new Error( _e1 );
			var id = character.id;
			var name = character.name.toLowerCase();
			if ( this._id_hash[ id ] ) throw new Error( _e2.replace( '%s', id ) );
			if ( this._name_hash[ name ] ) throw new Error( _e3.replace( '%s', name ) );
			// добавляем
			this._id_hash[ id ] =		character;
			this._name_hash[ name ] =	character;
			if ( this.hasEventListener( EE_A ) ) {
				var	event = new EEvent( EE_A );
				event.character = character;
				this.dispatchEvent( event );
			}
		};

		/**
		 * @method
		 * @param	{avangard.Character}	character
		 * @throws	{Error}					absent reference to the character
		 * @throws	{Error}					character with id never been added
		 * @throws	{Error}					character with name never been added
		 * @throws	{Error}					occurred desync name and id
		 */
		ChannelPrototype.removeCharacter = function(character) {
			if ( !character ) throw new Error( _e1 );
			var id = character.id;
			var name = character.name.toLowerCase();
			if ( !this._id_hash[ id ] ) throw new Error( _e2.replace( '%s', id ) );
			if ( !this._name_hash[ name ] ) throw new Error( _e3.replace( '%s', name ) );
			// удалим
			var	object = this._id_hash[ id ];
			if ( object !== this._name_hash[ name ] ) throw new Error( 'occurred desync name "' + name + '" and id "' + id + '"' );
			delete this._id_hash[ id ];
			delete this._name_hash[ name ];
			// обновим
			if ( this.hasEventListener( EE_R ) ) {
				var	event = new EEvent( EE_R );
				event.character = character;
				this.dispatchEvent( event );
			}
		};

		/**
		 * @method
		 * @param	{Number}	id
		 * @return	{avangard.Character}
		 */
		ChannelPrototype.getCharacterByID = function(id) {
			return this._id_hash[ id ] || null;
		};

		/**
		 * @method
		 * @param	{String}	name
		 * @return	{avangard.Character}
		 */
		ChannelPrototype.getCharacterByName = function(name) {
			return this._name_hash[ name.toLowerCase() ] || null;
		};

		/**
		 * @method
		 * @return	{Array}
		 */
		ChannelPrototype.getCharacters = function() {
			var	result = new Array();
			for ( var i in this._id_hash ) {
				result.push( this._id_hash[ i ] );
			}
			return result
		};

		/**
		 * @method
		 * @override
		 * подготавливает объект к удалению
		 */
		ChannelPrototype.dispose = function() {
			this.logger.dispose();
			this.logger = null;
			ChannelSuperPrototype.dispose.call( this );
		};

		/**
		 * @method
		 * @return	{String}
		 */
		ChannelPrototype.toString = function() {
			return '[Channel object]';
		};

		//--------------------------------------------------------------------------
		//
		//  Class methods
		//
		//--------------------------------------------------------------------------

		/**
		 * @static
		 * @method
		 * @return	{String}
		 */
		Channel.toString = function() {
			return '[class Channel]';
		};

		return Channel;

	}() );

}